/****************************************************************************
 * Copyright (C) 2009 SciTouch LLC
 * 
 * This file is part of Indigo toolkit.
 * 
 * This file may be distributed and/or modified under the terms of the
 * GNU General Public License version 3 as published by the Free Software
 * Foundation and appearing in the file LICENSE.GPL included in the
 * packaging of this file.
 * 
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 ***************************************************************************/

#include "base_cpp/output.h"
#include "molecule/molecule_tree_canonizer.h"
#include "molecule/molecule.h"

MoleculeTreeCanonizer::MoleculeTreeCanonizer (const Molecule &mol) :
TreeCanonizer(mol),
TL_CP_GET(_vertex_ranks)
{
   cb_vertex_rank = _vertex_rank;
   cb_vertex_code = _vertex_code;
   cb_edge_code = _edge_code;
   cb_edge_rank = _edge_rank;
   
   _vertex_ranks.clear_resize(mol.vertexEnd());
   
   if (cb_vertex_rank == 0)
      _vertex_ranks.zerofill();
   else if (mol.vertexCount() > 0)
   {
      QS_DEF(Array<_VertexLabel>, vertex_labels);

      vertex_labels.clear();

      int i;
      
      for (i = mol.vertexBegin(); i != mol.vertexEnd(); i = mol.vertexNext(i))
      {
         _VertexLabel &vl = vertex_labels.push();
         
         vl.idx = i;
         vl.label = mol.getAtom(i).label;
      }
      
      vertex_labels.qsort(_cmp_vlabels, 0);
      
      int rank = 0;
      int label = vertex_labels[0].label;
      
      _vertex_ranks[vertex_labels[0].idx] = rank;
      for (i = 1; i < vertex_labels.size(); i++)
      {
         _VertexLabel &vl = vertex_labels[i];
         
         if (vl.label != label)
         {
            label = vl.label;
            rank++;
         }
         _vertex_ranks[vl.idx] = rank;
      }
   }
   
}

int MoleculeTreeCanonizer::_cmp_vlabels (const _VertexLabel &a, const _VertexLabel &b, const void *context)
{
   return a.label - b.label;
}

void MoleculeTreeCanonizer::edgeCodesOff ()
{
   cb_edge_code = 0;
   cb_edge_rank = 0;
}

int MoleculeTreeCanonizer::_vertex_rank (const Graph &tree, int vertex_idx, const void *context)
{
   const MoleculeTreeCanonizer *self = (const MoleculeTreeCanonizer *)context;
   
   return self->_vertex_ranks[vertex_idx];
}

int MoleculeTreeCanonizer::_edge_rank (const Graph &tree, int edge_idx, const void *context)
{
   const Molecule &mol = (const Molecule &)tree;

   return mol.getBond(edge_idx).type;
}

void MoleculeTreeCanonizer::_vertex_code (const Graph &tree, int vertex_idx, Output &output)
{
   output.writeString(Element::toString(((const Molecule &)tree).getAtom(vertex_idx).label));
}

void MoleculeTreeCanonizer::_edge_code (const Graph &tree, int edge_idx, Output &output)
{
   const Molecule &mol = (const Molecule &)tree;

   int type = mol.getBond(edge_idx).type;

   if (type == BOND_SINGLE)
      output.writeChar('-');
   else if (type == BOND_DOUBLE)
      output.writeChar('=');
   else if (type == BOND_TRIPLE)
      output.writeChar('#');
   else
      output.writeChar('%');
}

void MoleculeTreeCanonizer::process (Output &output)
{
   perform(output, this);
}
